#ifndef GAMEENGINE_GEOMETRY_PLANE3D_H
#define GAMEENGINE_GEOMETRY_PLANE3D_H

#include <GameEngine/Geometry/geometry_settings.h>

#include <GameEngine/Geometry/Location/point3d.h>
#include <GameEngine/Geometry/Location/vector3d.h>
#include <GameEngine/Geometry/Lines/line3d.h>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif


//! Class used to represent 3D planes
/*!
 @note A 3D plane is an infinite planar surface embedded in a 3D space. It is made
       of an origin and a normal vector
 @note Most algorithms expect floating point operations. Type T should therefore
       not be an integer type
 @todo Setup unit tests
 */
template <class T>
class Plane3d {

public:
	Plane3d();
	Plane3d(const Point3d<T>& origin, const Vector3d<T>& normal);
	Plane3d(const Point3d<T>& p1, const Point3d<T>& p2, const Point3d<T>& p3);
	Plane3d(const Plane3d& rhs);
	virtual ~Plane3d();
	Plane3d& operator=(const Plane3d& rhs);

	Point3d<T>& origin();
	const Point3d<T>& origin() const;
	Vector3d<T>& normal();
	const Vector3d<T>& normal() const;

	bool coplanar(const Point3d<T>& rhs, const T& tolerance = 0.000001) const;
	bool intersection(const Line3d<T>& rhs, T& line_coordinate, IntersectionType::Type* type = nil) const;

	Point3d<T> closest_point(const Point3d<T>& rhs) const;
	Point3d<T> project(const Point3d<T>& rhs) const;
	bool project(const Point3d<T>& rhs, const Vector3d<T>& direction, Point3d<T>& impact) const;

	bool degenerate(const T& tolerance = 0.000001) const;

protected:
	//! Origin of the plane
	Point3d<T> origin_;

	//! Normal of the plane
	Vector3d<T> normal_;
};

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#include <GameEngine/Geometry/Surfaces/plane3d.hpp>

#endif
